package com.longway.core.toolbox.apidoc;

import com.jfinal.core.Action;
import com.jfinal.core.Controller;
import com.jfinal.core.JFinal;
import com.jfinal.kit.JsonKit;
import com.jfinal.kit.PropKit;
import com.jfinal.plugin.activerecord.CPI;
import com.jfinal.plugin.activerecord.Model;
import com.jfinal.plugin.activerecord.Table;
import com.longway.common.model.BaseUser;
import com.longway.core.toolbox.apidoc.annotation.ApiDoc;
import com.longway.core.toolbox.apidoc.annotation.ApiMethod;
import com.longway.core.toolbox.apidoc.annotation.ApiParam;
import com.longway.core.toolbox.apidoc.annotation.ApiParams;
import com.longway.core.toolbox.apidoc.annotation.ApiResponse;
import com.longway.core.toolbox.apidoc.models.ApiDocModel;
import com.longway.core.toolbox.apidoc.models.ApiMethodModel;
import com.longway.core.toolbox.apidoc.models.ApiModule;
import com.longway.core.toolbox.apidoc.models.ApiParamModel;
import com.longway.core.toolbox.apidoc.models.ApiParamsModel;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

/**
 * @author ryc
 * 2020年4月30日 上午11:13:58
 */
public class ApiDocKit{
	
    private static ApiModule apiModule;
    //controllerKey  Class<? extends Controller>
    private static Map<String,Class<? extends Controller>> apiControllers = new HashMap<String,Class<? extends Controller>>();
    //controllerKey  Map<String,Action>-- actionKey,action
    //private static Map<String,Map<String,Action>> apiActions = new HashMap<String,Map<String,Action>>();
    
    private static void getApiControllers(){
    	apiControllers.clear();
    	//apiActions.clear();
    	List<String> allActionKeys = JFinal.me().getAllActionKeys();
    	for (String actionKey : allActionKeys) {
  			String[] urlPara = new String[1];
  			Action action = JFinal.me().getAction(actionKey, urlPara);
  			Class<? extends Controller> controller = action.getControllerClass();
  			if(apiControllers.get(action.getControllerKey())==null){
  				apiControllers.put(action.getControllerKey(), controller);
  			}
  			/*if(apiActions.get(action.getControllerKey())==null){
  				apiActions.put(action.getControllerKey(), new HashMap<String,Action>());
  			}
  			apiActions.get(action.getControllerKey()).put(actionKey, action);*/
        }
    }
    
    public static ApiModule parseApiData(ApiModule apiModule){
    	//获取所有的controller
    	getApiControllers();
    	for(String controllerKey : apiControllers.keySet()){
    		Class<? extends Controller> controller = apiControllers.get(controllerKey);
    		//获取注解ApiDoc
        	ApiDoc apiDoc =  (ApiDoc)controller.getAnnotation(ApiDoc.class);
        	if(apiDoc != null){
        		ApiDocModel apidocModel = parseApiDoc(apiDoc,controllerKey);
            	Method[] methods = controller.getDeclaredMethods();
            	for(Method method : methods){
            		ApiMethod apiMethod = method.getAnnotation(ApiMethod.class);
            		if(apiMethod != null){
            			String actionKey = controllerKey+"/"+method.getName();
            			ApiMethodModel apimethodModel = parseApiMethod(apiMethod,actionKey);
                		if(apimethodModel != null){
                			ApiResponse apiResponse = method.getAnnotation(ApiResponse.class);
                			if(apiResponse!=null){
                				String result=null;
                				if(apiResponse.model()!=Object.class){
                					 result = jsonFormat(apiResponse.model());
                				}else if(apiResponse.result()!=null){
                					result = apiResponse.result();
                				}
                				apimethodModel.setParamsOut(result);
                			}
                			ApiParams apiParams = method.getAnnotation(ApiParams.class);
                			apimethodModel.setParamsIn(parseApiParams(apiParams));
                    		apidocModel.addMethodsModel(apimethodModel);
                		}
            		}
            	}
            	apiModule.addApiDocModel(apidocModel.getControllerKey(),apidocModel);
        	}
    	}
        return apiModule;
    }
    
    public static ApiDocModel parseApiDoc(ApiDoc apiDoc ,String controllerKey){
    	 if(apiDoc != null){
    		 return new ApiDocModel(apiDoc.title(), apiDoc.des(), apiDoc.version(),controllerKey,apiDoc.module());
    	 }
    	 return null;
    }
    
    public static ApiMethodModel parseApiMethod(ApiMethod apiMethod,String actionKey){
    	 if(apiMethod != null){
    		 return new ApiMethodModel(apiMethod.title(), apiMethod.des(), apiMethod.version(),actionKey,"Post");
    	 }
    	 return null;
    }
    
    public static ApiParamsModel parseApiParams(ApiParams apiParams){
    	 if(apiParams != null){
    		 ApiParamsModel paramsModel = new ApiParamsModel();
    		 ApiParam[] apiParam = apiParams.apiParams();
    		 for(int i=0;i<apiParam.length;i++){
    			 ApiParamModel apm = new ApiParamModel(apiParam[i].name(), apiParam[i].type(), apiParam[i].length(), apiParam[i].des(), apiParam[i].requried());
    			 if(apiParam[i].model()!=Object.class){
    				 paramsModel.setAddEntityClass(entityFormat(apiParam[i].model()));
    			 }
    			 paramsModel.addApiParamModel(apm);
    		 }
    		return paramsModel;
    	 }
    	 return null;
    }
    

	public static ApiModule getApiModule(){
    	if(apiModule == null){
    		apiModule = new ApiModule(PropKit.get("apiDocTitle"),PropKit.get("apiDocDes"));
    		return parseApiData(apiModule);
    	}
    	return apiModule;
    }
	
	
	public static void refreshApiModule(){
    	apiModule = new ApiModule(PropKit.get("apiDocTitle"),PropKit.get("apiDocDes"));
		parseApiData(apiModule);
    }
	
	public static String jsonFormat(Class c){
		StringBuffer sb = new StringBuffer();
		String json = null;
		try {
			Model model = (Model)c.newInstance();
			Map<String, Class<?>> map =CPI.getTable(model).getColumnTypeMap();
			sb.append("{");
			for(String key : map.keySet()){
				sb.append("\"").append(key).append("\"").append(":").append("\"").append(map.get(key).getSimpleName()).append("\"").append(",");
			}
			Field fields[] = c.getDeclaredFields();
			for(int i=0; i<fields.length; i++){
				String name = fields[i].getName();
				String type = fields[i].getType().toString();
				sb.append("\"").append(name).append("\"").append(":").append("\"").append(type).append("\"").append(",");
			}
			json  = sb.toString();
			json = json.substring(0, json.length()-1)+"}";
		} catch(Exception e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		return json;
	}
	
	public static String entityFormat(Class c){
		StringBuffer sb = new StringBuffer();
		String json = null;
		try {
			Model model = (Model)c.newInstance();
			Map<String, Class<?>> map =CPI.getTable(model).getColumnTypeMap();
			sb.append("{\n");
			for(String key : map.keySet()){
				sb.append("\"").append(key).append("\"").append(":").append("\"").append(map.get(key).getSimpleName()).append("\"").append(",\n");
			}
			json  = sb.toString();
			json = json.substring(0, json.length()-2)+"\n}";
		} catch(Exception e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		return json;
	}
}
